package la.iok.aone.monitor.youtube.service;

import la.iok.aone.monitor.youtube.mapper.YoutubeLinkMapper;
import la.iok.aone.monitor.youtube.model.YoutubeLink;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

@Service
public class YoutubeLinkService {
    private Logger logger = LoggerFactory.getLogger(getClass());
    @Value("${config.import.ignore.deleted:true}")
    private boolean ignoreImportDeleted;
    @Autowired
    private YoutubeLinkMapper youtubeLinkMapper;
    // 在方法是synchronized的情况下，其实可以不需要用到AtomicInteger 使用普通 int静态变量即可。
    private static AtomicInteger offset = new AtomicInteger(0);

    /**
     * 平滑的轮询，新加入的链接会逐渐追上较早加入链接的监控次数。
     * 监控Youtube链接. 每个链接调用一次，必须同步调用，否则一个链接同时被多次监控与需求不符。
     * 每次请求@Link pageSize数量的链接数进行监控
     * 1. 查询数据中最大监控次数。
     * 2. 如果最大监控次数大于0，则直接查询指定数量小于最大监控次数的链接。
     *   （注意：当查询到最后一页数据时，查询得到的结果集数量会小于页大小，这时需要从等于最大监控次数的链接中补齐一页链接数据）
     *    如果最大监控次数不大于0，表示当前还没开始进行监控过。则只需要查询一页数据返回即可。
     * 3. 修改监控次数自增1.
     * @param pageSize
     * @return
     */
    @Transactional
    public synchronized List<YoutubeLink> selectBySmoothPolling(int pageSize) {
        Integer maxMonitorCount = this.youtubeLinkMapper.maxOfMonitorCount();
        List<YoutubeLink> list = null;
        if (null != maxMonitorCount && 0 < maxMonitorCount) {
            list = this.youtubeLinkMapper.selectForPageMonitCountLess(maxMonitorCount, pageSize);
            if (list.size() < pageSize) {
                list.addAll(this.youtubeLinkMapper.selectForPage(pageSize - list.size()));
            }
        } else {
            list = this.youtubeLinkMapper.selectForPage(pageSize);
        }

        for (YoutubeLink youtubeLink: list) {
            this.youtubeLinkMapper.updateMonitor(youtubeLink.getId());
        }
        return list;
    }

    /**
     * 普通轮询，记录游标，每次从游标处获取指定数量的链接。
     * 新加入的链接只能等待下一次游标经过时才会被读取监控。
     * 在程序启动时，默认游标为0. 如果需要记录默认游标，则需要在程序启动时从数据库或其它地方读取保存的游标记录值。
     * 查询指定数量的记录，如果记录数小于pageSize的值，则重置游标的值，并补查询缺少数量的记录数。
     * 将监控次数自增，并修改监控时间为当前时间。
     * @param pageSize
     * @return
     */
    @Transactional
    public synchronized  List<YoutubeLink> selectByPolling(String catagory, int pageSize) {
        List<YoutubeLink> list = this.youtubeLinkMapper.getByPage(catagory, offset.getAndAdd(pageSize), pageSize);
        if (list.size() < pageSize) {
            int lessSize = pageSize - list.size();
            offset.set(lessSize);
            list.addAll(this.youtubeLinkMapper.getByPage(catagory,0, lessSize));
        }
        for (YoutubeLink youtubeLink: list) {
            this.youtubeLinkMapper.updateMonitor(youtubeLink.getId());
        }
        return list;
    }

    /**
     * 提供给多画面监控调用，用于下线Youtube链接，并给出原因。
     * @param id 待下线的Youtube链接编号
     * @param reason 下线理由
     */
    @Transactional
    public void offlineYoutubeLink(int id, String reason) {
        this.youtubeLinkMapper.offline(id, reason);
    }

    /**
     * 修改Youtube链接
     * @param youtubeLink
     * @return
     */
    @Transactional
    public int updateCheckResult(YoutubeLink youtubeLink) {
        return this.youtubeLinkMapper.updateCheckResult(youtubeLink);
    }

    /**
     * 用于Excel导入，插入或更新Youtube链接信息
     * @param youtubeLink
     */
    @Transactional
    public void insertOrUpdate(YoutubeLink youtubeLink) {
        YoutubeLink persistenceYoutubeLink = this.youtubeLinkMapper.findByFeedbackId(youtubeLink.getFeedbackId());
        if (null == persistenceYoutubeLink) {
            this.youtubeLinkMapper.insert(youtubeLink);
        } else if (persistenceYoutubeLink.isDelFlag()) {
            logger.warn("{} is deleted! Now it's comming back!", persistenceYoutubeLink.getLink());

            persistenceYoutubeLink.setTitle(youtubeLink.getTitle());
            persistenceYoutubeLink.setCategory(youtubeLink.getCategory());
            persistenceYoutubeLink.setFeedbackId(youtubeLink.getFeedbackId());
            // 重置检测错误次数
            persistenceYoutubeLink.setCheckErrorTimes(0);
            persistenceYoutubeLink.setDelFlag(false);

            this.youtubeLinkMapper.reinsert(persistenceYoutubeLink);
        } else {
            logger.debug("{}： {} existed! last check time [{}] consecutive error times[{}]",
                    persistenceYoutubeLink.getFeedbackId(), persistenceYoutubeLink.getLink(),
                    persistenceYoutubeLink.getCheckTime(), persistenceYoutubeLink.getCheckErrorTimes());
        }
    }

    /**
     * 删除链接
     * @param youtubeLink
     */
    public void delete(YoutubeLink youtubeLink) {
        delete(youtubeLink.getId());
    }

    /**
     * 删除链接
     * @param id
     */
    public void delete(int id) {
        this.youtubeLinkMapper.deleteById(id);
    }

    /**
     * 获取所有链接数量
     */
    public int countAll() {
        return this.youtubeLinkMapper.countAll();
    }
}
